/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufba.lasid.ds.fd.api;

import br.ufba.lasid.base.ResourceFactory;
import br.ufba.lasid.base.ResourceList;
import br.ufba.lasid.base.api.IComponent;
import br.ufba.lasid.base.api.IResource;
import br.ufba.lasid.base.api.IResourceFactory;
import br.ufba.lasid.base.api.IResourceList;
import br.ufba.lasid.base.api.IResourcetable;
import br.ufba.lasid.comm.HostList;
import br.ufba.lasid.comm.Hosttable;
import br.ufba.lasid.comm.api.ICommunicator;
import br.ufba.lasid.comm.api.IHost;
import br.ufba.lasid.utils.Agenda;

/**
 *
 * @author aliriosa
 */
public interface IFailureDetector extends IComponent {

    public enum ModuleTypes {

        PeriodicAction,
        StateReporter,
        MessageHandler,
        TimeoutHandler
    }

    public enum MessageKinds {

        CheckState, StateReport
    }

    public enum MonitoringStyles {

        Pull, Push
    }

    public void install(IFailureDetectorModule module) throws Exception;

    public void install(ICommunicator communicator) throws Exception;

    public void startup() throws Exception;

    public void buildup() throws Exception;

    public void buildupAndStartup() throws Exception;

    public void register(String hostID) throws Exception;

    public void register(String hostID, boolean isLocal) throws Exception;

    public void register(IHost host, boolean islocal) throws Exception;

    public boolean isRegistered(String hostID) throws Exception;

    public boolean isRegistered(IHost host) throws Exception;

    public HostList getRegisteredHosts() throws Exception;

    public Hosttable getHosttable() throws Exception;

    public IFailureDetectorPeriodicActionModule getPeriodicAction() throws Exception;

    public IFailureDetectorStateReporterModule getStateReporter() throws Exception;

    public IFailureDetectorMessageHandler getMessageHandler() throws Exception;

    public IFailureDetectorTimeoutHandler getTimeoutHandler() throws Exception;

    public ICommunicator getCommunicator() throws Exception;

    public IHost getLocalhost() throws Exception;
    
    public IHost getRemotehost() throws Exception;

    public IResource.States query(String resourceID) throws Exception;

    public boolean isUp(String resourceID) throws Exception;

    public boolean isDown(String resourceID) throws Exception;

    public boolean isUndefined(String resourceID) throws Exception;

    public MonitoringStyles getMonitoringStyle() throws Exception;

    public void setPeriod(long period) throws Exception;

    public void setTimeout(long period) throws Exception;

    public long getTimeout() throws Exception;

    public Agenda getAgenda() throws Exception;

    public static class Utils {

        public static String newMessage(MessageKinds type, IResourcetable resourcetable) throws Exception {
            ResourceList resources = new ResourceList();
            resources.addAll(resourcetable.values());

            String messageBody = "";
            String more = "";


            for (IResource resource : resources) {
                //resourceID1:resourceKind1:resourceState1;resourceID2:resourceKind2:resourceState2
                messageBody += more + resource.getAddress() + ":" + resource.getKind().name() + ":" + resource.getState().name();
                more = ";";
            }

            return newMessage(type, messageBody);
        }

        public static String newMessage(MessageKinds type, String messageBody) throws Exception {

            if (type != null) {
                return type.ordinal() + "/" + messageBody;
            }

            return "";
        }

        public static String newMessage(MessageKinds type) throws Exception {
            return newMessage(type, "");
        }

        public static MessageKinds getMessageType(String message) {

            if (message != null && message.contains("/")) {
                String type = message.substring(0, message.indexOf("/"));

                if (type.trim().length() > 0) {
                    int ord = Integer.valueOf(type);

                    return MessageKinds.values()[ord];
                }


            }

            return null;
        }

        public static String getMessageBody(String message) {

            if (message != null) {
                int i = message.indexOf("/");

                if (i > 0 && i < message.length()) {
                    return message.substring(i + 1);
                }
            }

            return "";
        }

        public static String getHostIDFromResourceAddress(String resourceAddress) {
            String hostID = resourceAddress.substring(resourceAddress.indexOf("@") + 1);
            if (hostID != null && !hostID.equals("null")) {
                return hostID;
            }

            return null;
        }

        public static IResourceList getResourceListFromMessage(String message) throws Exception {

            ResourceList resources = new ResourceList();
            String msgBody = getMessageBody(message);

            //msgBody = msgBody.substring(msgBody.indexOf("/")+1);

            String[] rpatterns = msgBody.split(";");

            IResourceFactory factory = ResourceFactory.getResourceFactory(IResource.Kinds.Base);//new Resource(null, rID, IResource.Types.Unknown);

            if (rpatterns != null && rpatterns.length > 0) {

                for (String rpattern : rpatterns) {

                    if (rpattern.isEmpty()) {
                        continue;
                    }

                    int i = rpattern.indexOf(":");
                    int j = rpattern.indexOf(rpattern, i + 1);

                    String rsrcAddress = rpattern.substring(0, i);
                    String rsrcKind = rpattern.substring(i + 1, j);
                    String rsrcState = rpattern.substring(j + 1);
                    String rsrcID = rsrcAddress.substring(0, rsrcAddress.indexOf("@"));

                    IResource resource = factory.create(rsrcID);
//                    
                    resource.setState(IResource.States.valueOf(rsrcState));
                    resource.setKind(IResource.Kinds.valueOf(rsrcKind));

                    resources.add(resource);

                }
            }
            return resources;
        }

        public static boolean isAHostID(String resourceAddress) {
            return resourceAddress.indexOf("@") < 0;
        }
    }
}
